Skip to content

Ruler: split oversized remote distributor writes - #16160

Merged
aknuds1 merged 5 commits into
mainfrom
arve/ruler-split-remote-distributor-writes
Aug 5, 2026
Merged

Ruler: split oversized remote distributor writes#16160
aknuds1 merged 5 commits into
mainfrom
arve/ruler-split-remote-distributor-writes

Conversation

@aknuds1

@aknuds1 aknuds1 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Remote ruler writes were previously sent as a single gRPC message, so large rule evaluation results could exceed ruler.distributor.grpc_client_config.max_send_msg_size. This PR derives a compression-safe effective payload limit, splits oversized Remote Write 1.0 requests at series boundaries, and sends the resulting requests sequentially. Each generated request has its own timeout and retry lifecycle.

Successful earlier requests aren't rolled back if a later request fails, so a failed rule evaluation can leave partially written results. The ruler emits one float or native-histogram sample per result series for each evaluation. Consequently, an individual result series exceeding the effective split limit cannot be losslessly subdivided. If this occurs, increase ruler.distributor.grpc_client_config.max_send_msg_size and configure the distributor's server.grpc_server_max_recv_msg_size to be at least as large. When compression is enabled, a series above the conservative effective limit may still succeed if its compressed payload fits within the configured transport limit; otherwise gRPC returns ResourceExhausted.

The implementation preserves request ownership and series ordering and reuses the RW1 write-request splitter already used by ingest storage to keep Kafka records within their configured size limit. The ruler adds compression-aware sizing, sequential gRPC sends, and per-request retries around that splitter. The cortex_ruler_remote_distributor_requests_per_write_request histogram reports how many remote requests each ruler write generates. This PR also fixes the RW1 splitter's protobuf embedded-message framing accounting and caps its initial preallocation for very small limits. The corresponding RW2 fixes are in #16295.

Checklist

  • Tests updated.
  • Documentation added.
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]. If changelog entry is not needed, please add the changelog-not-needed label to the PR.
  • about-versioning.md updated with experimental features. Not applicable: this PR doesn't add an experimental feature or configuration surface.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

💻 Deploy preview deleted (Mimir).

@ldufr

ldufr commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

🤖 Automated comment

The CHANGELOG has just been cut to prepare for the next release. Please rebase main and eventually move the CHANGELOG entry added / updated in this PR to the top of the CHANGELOG.md document. Thanks!

@aknuds1
aknuds1 force-pushed the arve/ruler-split-remote-distributor-writes branch from 4434c5d to b84ee28 Compare August 4, 2026 14:59
@aknuds1 aknuds1 added enhancement New feature or request component/ruler labels Aug 4, 2026
@aknuds1
aknuds1 force-pushed the arve/ruler-split-remote-distributor-writes branch from b84ee28 to 2f0ab5f Compare August 4, 2026 16:16
@aknuds1
aknuds1 force-pushed the arve/ruler-split-remote-distributor-writes branch 5 times, most recently from 08c87f4 to bdec8a2 Compare August 5, 2026 07:08
@aknuds1
aknuds1 marked this pull request as ready for review August 5, 2026 07:12
@aknuds1
aknuds1 requested review from a team as code owners August 5, 2026 07:12
@aknuds1
aknuds1 requested a review from juliusmh August 5, 2026 07:12
@aknuds1
aknuds1 force-pushed the arve/ruler-split-remote-distributor-writes branch from bdec8a2 to b7df148 Compare August 5, 2026 07:32
Remote ruler writes were previously sent as a single gRPC message, so large rule evaluation results could exceed the configured transport limit. Split Remote Write 1.0 requests by series at the gRPC maximum send size and send each part sequentially with independent retries.

Preserve request ownership and ordering, expose the number of generated requests, document partial-write semantics, and fix the RW1 splitter's protobuf size accounting and capacity estimates.

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
@aknuds1
aknuds1 force-pushed the arve/ruler-split-remote-distributor-writes branch from b7df148 to e3e3ac8 Compare August 5, 2026 07:44
The ruler splits remote writes along series boundaries so that they fit within `ruler.distributor.grpc_client_config.max_send_msg_size`.
When compression is enabled, the ruler reserves a conservative amount of space for compression framing, so it can split a write slightly below the configured transport limit.
It sends the resulting requests sequentially, with independent timeouts and retries; each request also consumes a separate gRPC client rate-limit token when rate limiting is enabled.
Requests accepted before a later request fails aren't rolled back.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] I don't think there's a way to roll-back a write?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's any claim it's possible either, right? It's just clarified they're not going to be undone (rolled back).

Comment thread pkg/mimirpb/split.go
//
// The returned requests may still retain references to fields in the original WriteRequest, i.e. they are tied to its lifecycle.
func SplitWriteRequestByMaxMarshalSize(req *WriteRequest, reqSize, maxSize int) []*WriteRequest {
if maxSize <= 0 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] I think it's safe to assume maxSize is a non-zero positive integer.

Comment thread pkg/ruler/distributor_client.go Outdated
Comment thread pkg/mimirpb/split.go
estimatedTimeseriesPerPartialReq := (len(req.TimeseriesRW2) / estimatedPartialReqs) + 1 // +1 is to round up

newPartialReq := func() (*WriteRequest, int) {
r := &WriteRequest{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know u didn't touch this - but do you mind using the newPartialWriteRequest func here too? This would fix the missing SkipLabelCountValidation issue here too. Note: you'd have to manually initialize TimeseriesRW2 here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see #16295.

aknuds1 and others added 4 commits August 5, 2026 14:40
Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
Co-authored-by: Julius Hinze <julius.hinze@grafana.com>
Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
@aknuds1
aknuds1 requested a review from juliusmh August 5, 2026 13:15
@aknuds1
aknuds1 merged commit 9ae50e8 into main Aug 5, 2026
174 of 175 checks passed
@aknuds1
aknuds1 deleted the arve/ruler-split-remote-distributor-writes branch August 5, 2026 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants